/**
 * @Author: your name
 * @Date: 2021-11-28 11:36:01
 * @LastEditTime: 2021-11-28 12:00:58
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \undefinede:\实验室\LiDAR\激光桶程序\Drv\Livox_IRQ_drv.c
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <asm/irq.h>
#include <linux/of_irq.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/interrupt.h>

static struct class *Livox_class;
static struct device *Livox_class_devs;
struct device_node* pdev_node1;
unsigned int dev_irqnum1;
volatile unsigned int ms_count;
volatile unsigned long *PL_irq_base;   
static volatile unsigned char  Livox_trigger_flag = 0;
#define LIVOX_IRQ  _IOR('l',1,int)
int Livox_MAJOR;

static DECLARE_WAIT_QUEUE_HEAD(Livox_waitq);

//IRQ function
static irqreturn_t Livox_irq(int irq, void *dev_id)
{
	//PL端触发PS中断，表示已触发传感器采集，准备接收时间戳
	 Livox_trigger_flag=1;
	//唤醒该采集进程
	 wake_up_interruptible(&Livox_waitq);
     return IRQ_HANDLED;
}

static int Livox_irq_open(struct inode * inode, struct file * filp)
{
		//与设备树中的节点CAM_IRQ匹配
        pdev_node1= of_find_compatible_node(NULL, NULL, "LIVOX_IRQ");
        if(pdev_node1==NULL)
          {
                printk("can't find the device ");
          }
        else
         {
                printk("the device name is %s\r\n",pdev_node1->name);
          }
        dev_irqnum1 = irq_of_parse_and_map(pdev_node1, 0);
		//申请中断
        //irq_number     irq_function    trigger_mode                   irq_name
        int ret1;
        ret1=request_irq(dev_irqnum1,  Livox_irq,  IRQF_TRIGGER_RISING,"LIVOX_IRQ",NULL);
        
        if(ret1){
            printk("request LIVOX_INT failed! ret = %d\n", ret1);
            return -1;
        }
        else{
            printk("dev is open!");
            return 0;
        }
}

static void reset_PL(void)
{
	volatile unsigned long *PL_base1;       
	volatile unsigned long *PL_base2;       
	
	PL_base1=ioremap(0xF8000008,1);
	PL_base2=ioremap(0xF8000240,1);
	iowrite32(57101,PL_base1);  //reset PL
	iowrite32(1,PL_base2);
	udelay(1);
	iowrite32(57101,PL_base1);  //reset end
	iowrite32(0,PL_base2);

}

static long Livox_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
	int tmp;
	if(_IOC_TYPE(cmd)!='l')
	return -ENOTTY ;
	switch(cmd)
	{
		case LIVOX_IRQ:
		{	
			//等待采集信号到来 阻塞该进程直到start_trigger_flag==1成立
			wait_event_interruptible(Livox_waitq, (Livox_trigger_flag==1));
			//清除采集信号
			Livox_trigger_flag = 0;
			break;
		}
		default: break;
    }
	return tmp;
}

int Livox_irq_close(struct inode * inode, struct file * filp)
{
        free_irq(dev_irqnum1,NULL);
        return 0;
}

static const struct file_operations Livox_irq_fops =

{
        .owner = THIS_MODULE,
        .open = Livox_irq_open,
        .release=Livox_irq_close,
        .unlocked_ioctl = Livox_ioctl,
        
};

static int Livox_init(void)
{
        Livox_MAJOR=register_chrdev(0,"Livox_irq_dec",&Livox_irq_fops);// register the char device
        //create a class
        Livox_class=class_create(THIS_MODULE,"Livox_irq_dec");
        //create devices nod
        Livox_class_devs=device_create(Livox_class,NULL,MKDEV(Livox_MAJOR,0),NULL,"Livox_irq");

        printk("LIVOX_IRQ Module init complete!\n");
   return 0;
}

static void Livox_exit(void)
{
        printk("LIVOX_IRQ Module exit!\n");

        unregister_chrdev(Livox_MAJOR,"Livox_irq_dec");     //remove char device
        device_unregister(Livox_class_devs);
        class_destroy(Livox_class);
        return 0;
}

module_init(Livox_init);
module_exit(Livox_exit);

MODULE_LICENSE("GPL");
